#include "PSSpray.h"
#include <ctime>

#ifdef PIX
//#undef PIX
#endif

PSSpray::PSSpray() : height(1.5f), g_device(0), g_context(0), srv_alpha(0), srv_noise_texture(0), vb_particles(0), vb_particles_2(0),
					 IA_Spray(0), bActive(true)
{
	
}

PSSpray::~PSSpray()
{
	try
	{
		if (g_device)
			g_device->Release();
		if (g_context)
			g_context->Release();
		if (srv_noise_texture)
			srv_noise_texture->Release();
		if (srv_alpha)
			srv_alpha->Release();
		if (vb_particles)
			vb_particles->Release();
		if (vb_particles_2)
			vb_particles_2->Release();
		if (IA_Spray)
			IA_Spray->Release();
	}
	catch(...)
	{
		MessageBoxA(0, "exception thrown in  destructor", 0, 0);
	}
}


void PSSpray::Update(float dt)
{

}

void PSSpray::draw(CXMMATRIX mVP, const XMFLOAT4& pos, float dt)
{
#ifndef PIX
	if (!bActive) return;

	// Save state
	ID3D11InputLayout* current_IA;
	g_context->IAGetInputLayout(&current_IA);

	D3D11_PRIMITIVE_TOPOLOGY current_primitive_topology;
	g_context->IAGetPrimitiveTopology(&current_primitive_topology);
	//////////////////////////////////////////////////////////////////////////


	// Set Topology
	g_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
	
	g_context->IASetInputLayout(IA_Spray);


	// Set Vertex Buffer
	UINT stride = sizeof(Particle);
	UINT offset = 0;
	g_context->IASetVertexBuffers(0, 1, &vb_particles, &stride, &offset);

	// Set Stream-Out Buffer
	g_context->SOSetTargets(1, &vb_particles_2, &offset);


	// Set effect Variables
	ID3DX11EffectMatrixVariable* fx_m_VP;
	ID3DX11EffectVectorVariable* fx_p_eye_pos;
	ID3DX11EffectShaderResourceVariable* fx_noise_texture;

		fx_m_VP = getFX()->GetVariableByName("m_VP")->AsMatrix();
		fx_m_VP->SetMatrix((float*)&mVP);
		
		fx_p_eye_pos = getFX()->GetVariableByName("p_eye_pos")->AsVector();
		fx_p_eye_pos->SetFloatVector((float*)&pos);

		fx_noise_texture = getFX()->GetVariableByName("noise_texture")->AsShaderResource();
		fx_noise_texture->SetResource(srv_noise_texture);

		ID3DX11EffectScalarVariable* fx_dt = getFX()->GetVariableByName("dt")->AsScalar();
		fx_dt->SetFloat(dt);

		ID3DX11EffectScalarVariable* fx_height = getFX()->GetVariableByName("height")->AsScalar();
		fx_height->SetFloat(height);

	// Get technique - Draw()
	ID3DX11EffectTechnique* tech = getFX()->GetTechniqueByName("Particles_SO");
	tech->GetPassByIndex(0)->Apply(0, g_context);
	g_context->Draw(num_particles, 0);


	
	// Un-bind Stream-Out Buffer
	ID3D11Buffer* buff_empty[1] =  {0};
	g_context->SOSetTargets(1, buff_empty, &offset);
	// Set Vertex Buffer
	g_context->IASetVertexBuffers(0, 1, &vb_particles_2, &stride, &offset);
	
	// Variables
	ID3DX11EffectShaderResourceVariable*	fx_alpha = getFX()->GetVariableByName("tex_alpha")->AsShaderResource();
	fx_alpha->SetResource(srv_alpha);

	// Get Technique - Draw()
	tech = getFX()->GetTechniqueByName("Particles_Draw");
	tech->GetPassByIndex(0)->Apply(0, g_context);
	g_context->DrawAuto();


	/////////////////////////////////////////
	// Restore state
	g_context->IASetPrimitiveTopology(current_primitive_topology);
	if (current_IA) {
		g_context->IASetInputLayout(current_IA);
		current_IA->Release();
	}

	// Swap buffers' addresses
	ID3D11Buffer* tmp;
	tmp = vb_particles;
	vb_particles = vb_particles_2;
	vb_particles_2 = tmp;

	g_context->OMSetDepthStencilState(0, 0);
#endif
}


void PSSpray::init(ID3D11Device* g_dev, ID3D11DeviceContext* g_ctx)
{

	g_device = g_dev;
	g_device->AddRef();

	g_context = g_ctx;
	g_ctx->AddRef();

	createEffect("../Desert_Island/shaders/particles.fxo", g_device);

	// Input layout - Spray IA
	D3D11_INPUT_ELEMENT_DESC leaf_layout[] = {
		{ "POSITION", 0,  DXGI_FORMAT_R32G32B32_FLOAT,    0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "VELOCITY", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "LIFE", 0,    DXGI_FORMAT_R32_FLOAT   , 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};

	D3DX11_PASS_DESC passDesc;
	ID3DX11EffectTechnique* tech = getFX()->GetTechniqueByName("Particles_SO");
	tech->GetPassByIndex(0)->GetDesc(&passDesc);

	HRESULT hr = g_device->CreateInputLayout(leaf_layout, 3, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &IA_Spray);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating IA spray", 0, 0);


	D3D11_BUFFER_DESC vb_desc;
	vb_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
	vb_desc.ByteWidth = sizeof(Particle) * num_particles;
	vb_desc.CPUAccessFlags = vb_desc.MiscFlags = 0;
	vb_desc.StructureByteStride = 0;
	vb_desc.Usage = D3D11_USAGE_DEFAULT;

	Particle p[num_particles];


	srand((UINT)time(0));

	for (int i=0; i<num_particles; ++i)
	{
		float angle = 6.28f * (i/(float)num_particles);
		
		
		float radius_scale = (float)rand();
		radius_scale = ((int)radius_scale % 100) / (float)100;
		radius_scale = radius_scale * 2.0f - 1.0f;

		float radius = 1.35f * radius_scale;

		p[i].position.x = cos(angle)	* radius;
		p[i].position.y = 0.228f		* 1.0f;
		p[i].position.z = -sin(angle)	* radius;

		// velocity 
		XMFLOAT3 v = XMFLOAT3(p[i].position.x, 0.0f, p[i].position.z);
		// vel = pos.xz
		XMVECTOR vel = XMLoadFloat3(&v);
		// normalize
		XMVector3Normalize(vel);
		// negate so it points towards the island
		vel = -vel;
		// store in v
		XMStoreFloat3(&v, vel);
		// store in velocity
		p[i].velocity = v;

		p[i].life = (float)(rand() % 1000 + 1);

	}



	D3D11_SUBRESOURCE_DATA vb_data;
	vb_data.pSysMem = p;
	vb_data.SysMemPitch = vb_data.SysMemSlicePitch = 0;

	hr = g_device->CreateBuffer(&vb_desc, &vb_data, &vb_particles);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating particles buffer", 0, 0);


	hr = g_device->CreateBuffer(&vb_desc, 0, &vb_particles_2);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating particles buffer", 0, 0);


	hr = D3DX11CreateShaderResourceViewFromFile(g_device, L"../Desert_Island/media/noise_texture.jpg", NULL, NULL, &srv_noise_texture, 0);
	if (FAILED(hr))
		MessageBoxA(0, "Error create noise texture SRV", 0, 0);


	hr = D3DX11CreateShaderResourceViewFromFile(g_device, L"../Desert_Island/media/drop.png", NULL, NULL, &srv_alpha, 0);
	if (FAILED(hr))
		MessageBoxA(0, "Error create noise texture SRV", 0, 0);


	

}




void PSSpray::setHeight(float v)
{ 
	height = v; 
}